package com.yizhiliulianta.wx.redis;

import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * RedisUtil工具类
 * 这个类封装了一些常用的Redis操作，简化了Redis的使用
 * 使用Spring的RedisTemplate来与Redis进行交互
 */
@Component
@Slf4j
public class RedisUtil {

    @Resource
    private RedisTemplate redisTemplate; // 使用Spring的RedisTemplate来与Redis进行交互

    private static final String CACHE_KEY_SEPARATOR = "."; // 缓存Key的分隔符

    /**
     * 构建缓存key
     * 将传入的多个字符串用指定的分隔符连接起来，构建一个缓存key
     *
     * @param strObjs 多个字符串
     * @return 连接后的缓存key
     */
    public String buildKey(String... strObjs) {
        return Stream.of(strObjs).collect(Collectors.joining(CACHE_KEY_SEPARATOR));
    }

    /**
     * 是否存在key
     * 判断Redis中是否存在指定的key
     *
     * @param key 缓存key
     * @return 存在返回true，否则返回false
     */
    public boolean exist(String key) {
        return redisTemplate.hasKey(key);
    }

    /**
     * 删除key
     * 从Redis中删除指定的key
     *
     * @param key 缓存key
     * @return 删除成功返回true，否则返回false
     */
    public boolean del(String key) {
        return redisTemplate.delete(key);
    }

    /**
     * set(不带过期)
     * 将字符串值存入Redis，不设置过期时间
     *
     * @param key 缓存key
     * @param value 缓存值
     */
    public void set(String key, String value) {
        redisTemplate.opsForValue().set(key, value);
    }

    /**
     * set(带过期)
     * 将字符串值存入Redis，并设置过期时间
     *
     * @param key 缓存key
     * @param value 缓存值
     * @param time 过期时间
     * @param timeUnit 时间单位
     * @return 设置成功返回true，否则返回false
     */
    public boolean setNx(String key, String value, Long time, TimeUnit timeUnit) {
        return redisTemplate.opsForValue().setIfAbsent(key, value, time, timeUnit);
    }

    /**
     * 获取string类型缓存
     * 从Redis中获取字符串值
     *
     * @param key 缓存key
     * @return 缓存值
     */
    public String get(String key) {
        return (String) redisTemplate.opsForValue().get(key);
    }

    /**
     * 添加元素到ZSet
     * 将指定元素添加到有序集合（ZSet）中
     *
     * @param key 缓存key
     * @param value 元素值
     * @param score 元素的分数
     * @return 添加成功返回true，否则返回false
     */
    public Boolean zAdd(String key, String value, Long score) {
        return redisTemplate.opsForZSet().add(key, value, Double.valueOf(String.valueOf(score)));
    }

    /**
     * 获取ZSet的元素数量
     * 获取有序集合（ZSet）中元素的数量
     *
     * @param key 缓存key
     * @return 元素数量
     */
    public Long countZset(String key) {
        return redisTemplate.opsForZSet().size(key);
    }

    /**
     * 获取ZSet中的元素范围
     * 获取有序集合（ZSet）中指定范围内的元素
     *
     * @param key 缓存key
     * @param start 起始位置
     * @param end 结束位置
     * @return 元素集合
     */
    public Set<String> rangeZset(String key, long start, long end) {
        return redisTemplate.opsForZSet().range(key, start, end);
    }

    /**
     * 从ZSet中移除元素
     * 从有序集合（ZSet）中移除指定元素
     *
     * @param key 缓存key
     * @param value 元素值
     * @return 移除的元素数量
     */
    public Long removeZset(String key, Object value) {
        return redisTemplate.opsForZSet().remove(key, value);
    }

    /**
     * 从ZSet中移除多个元素
     * 从有序集合（ZSet）中移除指定集合中的所有元素
     *
     * @param key 缓存key
     * @param value 要移除的元素集合
     */
    public void removeZsetList(String key, Set<String> value) {
        value.forEach(val -> redisTemplate.opsForZSet().remove(key, val));
    }

    /**
     * 获取ZSet中元素的分数
     * 获取有序集合（ZSet）中指定元素的分数
     *
     * @param key 缓存key
     * @param value 元素值
     * @return 元素的分数
     */
    public Double score(String key, Object value) {
        return redisTemplate.opsForZSet().score(key, value);
    }

    /**
     * 获取ZSet中指定分数范围内的元素
     * 获取有序集合（ZSet）中指定分数范围内的元素
     *
     * @param key 缓存key
     * @param start 起始分数
     * @param end 结束分数
     * @return 元素集合
     */
    public Set<String> rangeByScore(String key, long start, long end) {
        return redisTemplate.opsForZSet().rangeByScore(key, Double.valueOf(String.valueOf(start)), Double.valueOf(String.valueOf(end)));
    }

    /**
     * 增加ZSet中指定元素的分数
     * 增加有序集合（ZSet）中指定元素的分数
     *
     * @param key 缓存key
     * @param obj 元素值
     * @param score 要增加的分数
     * @return 增加后的分数
     */
    public Object addScore(String key, Object obj, double score) {
        return redisTemplate.opsForZSet().incrementScore(key, obj, score);
    }

    /**
     * 获取ZSet中指定元素的排名
     * 获取有序集合（ZSet）中指定元素的排名
     *
     * @param key 缓存key
     * @param obj 元素值
     * @return 元素的排名
     */
    public Object rank(String key, Object obj) {
        return redisTemplate.opsForZSet().rank(key, obj);
    }
}